/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package entities;

import java.awt.Color;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * The Cateforie class is used to create catégories for the actions.
 * @author chocoseb
 */
public class Categorie {

    private String _name;
    private Color _color;
    private Categorie _parent; // The parent categories
    private ArrayList<Categorie> _childList = new ArrayList<Categorie>();

     /**
     * The default path and file name for the file that contains the categories
     */
    public final static String DEFAULT_PATH = "categories.dat";

    /**
     * The list
     */
    private static ArrayList<Categorie> CATEGORIE_LIST = Categorie.loadAll();

    /**
     * Create a new Categorie with basic information
     */
    public Categorie(){
        _name = "New";
        _color = new Color(255,0,0);
        _parent = null;

    }

    /**
     * Create a new Categorie with the information stored into a file
     * @param in The DataInputStream in wich the information will be taken from.
     * @param list The list of all the Categorie currently open for that file.
     * @throws IOException If file is corrupted
     */
    public Categorie(DataInputStream in, ArrayList<Categorie> list) throws IOException {
        _name = in.readUTF();
        _color = new Color(in.readInt(),in.readInt(),in.readInt());
        String s_parent = in.readUTF();
        if (s_parent.equals("root")){
            _parent = null;
        }else{
            _parent = Categorie.findByName(s_parent, list);
            if (_parent != null){
                _parent.addChild(this);
            }
        }
    }

    public Color getColor() {
        return _color;
    }

    public void setColor(Color _color) {
        this._color = _color;
    }

    public String getName() {
        return _name;
    }

    public void setName(String _name) {
        this._name = _name;
    }

    /**
     * Get the parent Categorie
     * @return A Categorie object or null if there is no parent.
     */
    public Categorie getParent() {
        return _parent;
    }

    public void setParent(Categorie _parent) {
        this._parent = _parent;
    }

    @Override
    public String toString() {
        return _name;
    }

    /**
     * Add a child to this categorie
     * @param child
     */
    public void addChild(Categorie child){
        _childList.add(child);
    }

    /**
     * Check if the categorie can be deleted (If it has child items)
     * @return true or false
     */
    public boolean canBeSafelyDeleted(){
        return _childList.isEmpty();
    }

    /**
     * Save the categorie in an open file
     * @param out The DataOutputStream in wich the Categorie will be stored
     * @throws IOException If file is corrupted.
     */
    public void save(DataOutputStream out) throws IOException{
        out.writeUTF(_name);
        out.writeInt(_color.getRed());
        out.writeInt(_color.getGreen());
        out.writeInt(_color.getBlue());
        if (_parent == null){
            out.writeUTF("root");
        }
        else{
            out.writeUTF(_parent.getName());
        }
    }

    /**
     * Save all the categories in a list in the default file used to stored them.
     * @param p_list List of all the categories.
     */
    public static void saveAll (ArrayList<Categorie> p_list){
        try {
            DataOutputStream out = new DataOutputStream(new FileOutputStream(DEFAULT_PATH));
            Collections.sort(p_list, Categorie.getComparator());
            for (Categorie c : p_list) {
                c.save(out);
            }
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Load all the categories from the default file used in storing them
     * @return A list of categorie that can be empty but never null
     */
    public static ArrayList<Categorie> loadAll(){
        ArrayList<Categorie> list = new ArrayList<Categorie>();
        try {
            DataInputStream in = new DataInputStream(new FileInputStream(DEFAULT_PATH));
            while (in.available() > 0){
                list.add(new Categorie(in, list));
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Categorie.CATEGORIE_LIST = list;
        return list;
    }

    public static ArrayList<Categorie> getCategorieList(){
        if (CATEGORIE_LIST == null){
            return loadAll();
        }
        return CATEGORIE_LIST;
    }

    public ArrayList<Categorie> getChildList(){
        return _childList;
    }

    /**
     * Find a Categorie in the list from her name.
     * @param name The name of the researched Categorie
     * @param list The list that contains the categories
     * @return The found Categorie or null if none is found.
     */
    public static Categorie findByName(String name, ArrayList<Categorie> list){
        for(Categorie c : list){
            if(c.getName().equals(name)){
                return c;
            }
        }
        return null;
    }

    /**
     * Compare the categories
     * They will be listed in alphabéthical order with the roots categories on top.
     * @return The comparator object.
     */
    public static ComparatorCategories getComparator()
    {
        return new ComparatorCategories();
    }

    public static class ComparatorCategories implements Comparator<Categorie>
    {
      ComparatorCategories()
      {
      }
      public int compare(Categorie categorie1, Categorie categorie2)
      {   
          if (categorie1.getParent() == null  && categorie2.getParent() == null){
            return categorie1.getName().compareTo(categorie2.getName());
          }
          else if (categorie1.getParent() == null){
            return -1;
          }
          else if (categorie2.getParent() == null){
            return 1;
          }
          else{
              int result = 0;
              result = categorie1.getParent().getName().compareTo(categorie2.getParent().getName());
              if (result == 0){
                result = categorie1.getName().compareTo(categorie2.getName());
              }
              return result;
          }
      }

    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Categorie) {
            Categorie categorie = (Categorie) obj;
            if (categorie.getName().equals(this.getName())) {
                return true;
            }
        }
        return false;
    }



}
